# -*- coding: utf-8 -*-


# cmap2owl -- Helper application to convert from concept maps to OWL ontologies
# Copyright (c) 2008-2013  Rodrigo Rizzi Starr
#  
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#  
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#  
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


'''
Searches the CMap for adjective phrases, that is, phrases where the linguistic
rule AdjectivePhrase or DerivedClass returns positive and generates some derived
classes inferences from the phrase structure.

@author: Rodrigo Rizzi Starr
@copyright: Copyright © 2008-2013 Rodrigo Rizzi Starr
@license: MIT License
@contact: rodrigo.starr@gmail.com
'''


from CMap2Prolog import assemblyQuery
from infoProvider import TextGenInfoProvider
from mapperRule import MapperRule
from mapperQuestion import MapperQuestion
from linguisticRules import AdjectivePhrase, DerivedClass
from log import log
log.debug('Loaded...')


class AdjectivePhraseRule(MapperRule):
    'Infers the existence of a superclass from the text structure'

    def __init__(self, db):

        # Rules to create questions from the text identification phase
        rules = [
                 'inferenceGroup(derivedClasses, '
                                '[derivedClass(_, _, _, _, _)])',

                 'class(Concept) :- derivedClass(Concept, _, _, _, _)',

                 'isTrue(class(Id)) :- isTrue(derivedClass(Id, _, _, _, _))',
                     
                 'classOWL(DerivedId) :-'
                    'isTrue(derivedClass(DerivedId, _, _, _, _))',
                 'classOWL(Superclass) :-'
                    'isTrue(derivedClass(_, Superclass, _, _, _))',
                 'subclassOWL(Subclass, Superclass) :-'
                    'isTrue(derivedClass(Subclass, Superclass, _, _, _))',
                   ]
          
        MapperRule.__init__(self, 'AdjectivePhrases', db, rules)
      
    def createRule(self, phrases=[]):
        '''For each phrase in the cmap, check for the existence of an adjective
           phrase and creates possible classes for de main and derived
           concepts. We use both AdjectivePhrases and DerivedClass rules.
        '''

        # We have to tell prolog that we will use a dynamic predicate
        self.db.dynamic('derivedClass/5')
        
        # Now we apply the linguistic rule for each phrase
        ap = AdjectivePhrase()
        dc = DerivedClass()

        results = []
        for phrase in phrases:
            results.extend(ap.apply(phrase))
            results.extend(dc.apply(phrase))

        # We keep track of asserted facts because a node is part of several
        # phrases (this phrase structure is useful but not very
        # efficient). Also, sometimes both rules may give a true positive.
        assertedFacts = set()
        for result in results:
            # The predicate form is:
            # derivedClass(DerivedId, BaseClass, DerivedClass, 
            #                         BaseClassText, DerivedClassText)
            # (It follows the same structure of AdjectivePhraseResult)
            fact = ('derivedClass(%(id)s, %(baseClass)s, %(derivedClass)s, '
                                 '%(baseClassText)s, %(derivedClassText)s)')
            data = {'id': result.nodeId,
                    'baseClass': result.baseClass,
                    'derivedClass': result.derivedClass,
                    'baseClassText': result.baseClassText,
                    'derivedClassText': result.derivedClassText,
                    'baseClassTextLow': result.baseClassText.lower(),
                    }
            fact = assemblyQuery(fact, data)
            
            label = 'label(%(baseClass)s, %(baseClassText)s)'
            label = assemblyQuery(label, data)
            
            llabel = 'llabel(%(baseClass)s, %(baseClassTextLow)s)'
            llabel = assemblyQuery(llabel, data)
            
            if fact not in assertedFacts:
                assertedFacts.add(fact)
                self.db.assertz(fact)
            if label not in assertedFacts:
                assertedFacts.add(label)
                self.db.assertz(label)
            if llabel not in assertedFacts:
                assertedFacts.add(llabel)
                self.db.assertz(llabel)
                
                
        # This will assert all prolog rules. Must be done before we process the
        # phrases
        MapperRule.createRule(self, phrases)
            
    def getQuestions(self):
        '''Returns a list of questions if a certain concept can be a class'''
        
        questions = []
        query = ('possible(derivedClass(Subclass, Superclass, _, '
                                       'SuperLabel, SubLabel))')
        
        classes = list(self.db.query(query))
        
        for answer in classes:
            answer['Ids'] = [answer['Subclass']]
            questions.append(MapperQuestion(
                self.db,
                answer,
                'Is "<b>%(SubLabel)s</b>" a type of "<b>%(SuperLabel)s</b>"?',
                'derivedClass(%(Subclass)s, %(Superclass)s, _, '
                             '%(SuperLabel)s, %(SubLabel)s)',
                 helpFile = "adjectivePhrase",
            ))
            
        return questions
      
    def getInfoProvider(self):
        'Returns an info provider about classes and individuals'
        
        return MapperRule.getInfoProvider(self) #infoProvider
        
        
    
